package com.qipay.utils;

import org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.commons.lang3.StringUtils;
import org.dom4j.*;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.SAXException;

import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * Created by Administrator on 2016/7/27.
 */
public class XmlUtils {

    static Logger logger = LoggerFactory.getLogger(XmlUtils.class);

    /*
    * 把文档转化为 map
    * @param xml 文档内容
    * **/
    public static Map<String, Object> toMap(String xml) throws ParserConfigurationException,
            IOException, SAXException, DocumentException {
        if (StringUtils.isEmpty(xml)) {
            return new HashMap<String, Object>();
        }

        SAXReader reader = new SAXReader();
        Document document = DocumentHelper.parseText(xml);
        Element root = document.getRootElement();

        Map<String, Object> resultMap = new HashMap<String, Object>();
        for (Iterator it = root.elementIterator(); it.hasNext(); ) {
            Element element = (Element) it.next();
            String name = element.getName();
            String value = element.getTextTrim();
            if (StringUtils.isNoneEmpty(name, value)) {
                resultMap.put(name, value);
            }
        }
        return resultMap;
    }

    /*
    * 把 map转化为XML
    * @param map 文档内容
    * @param rootName 根目录名称
    * **/
    public static String toString(Map<String, Object> map, String rootName) throws IOException {
        if (StringUtils.isEmpty(rootName)) {
            rootName = "xml";
        }

        if (map == null || map.size() == 0) {
            return String.format("<%s></%s>", rootName, rootName);
        }
        ByteArrayOutputStream outputStream = null;
        XMLWriter writer = null;
        String xml = null;
        try {
            outputStream = new ByteArrayOutputStream();

            OutputFormat format = new OutputFormat();
            format.setSuppressDeclaration(true);
            writer = new XMLWriter(outputStream, format);

            Element root = DocumentHelper.createElement(rootName);
            map.forEach((key, val) -> {
                Element childElm = null;
                if (StringUtils.isNotEmpty(key) && val != null) {
                    childElm = DocumentHelper.createElement(key);
                    if (val instanceof String) {
                        CDATA cdata = DocumentHelper.createCDATA(val.toString());
                        childElm.add(cdata);
                    } else {
                        childElm.setText(val.toString());
                    }
                    root.add(childElm);
                }
            });

            Document document = DocumentHelper.createDocument(root);
            writer.write(document);
            writer.flush();

        } catch (Exception ex) {
            logger.error(ex.toString());
        } finally {
            if (writer != null) {
                writer.close();
            }

            if (outputStream != null) {
                xml = outputStream.toString();
                outputStream.close();
            }
        }
        return xml;
    }

    /**
     * 将Map对象通过反射机制转换成Bean对象
     *
     * @param map   存放数据的map对象
     * @param clazz 待转换的class
     * @return 转换后的Bean对象
     * @throws Exception 异常
     */
    public static Object mapToBean(Map<String, Object> map, Class clazz) throws Exception {
        Object obj = clazz.newInstance();
        if (map != null && map.size() > 0) {
            for (Map.Entry<String, Object> entry : map.entrySet()) {
                String propertyName = entry.getKey();
                Object value = entry.getValue();
                String setMethodName = getMethodNameFromProperties(propertyName);
                Field field = getClassField(clazz, getPropertyFromProperties(propertyName));
                if (field != null) {
                    Class fieldTypeClass = field.getType();
                    value = convertValType(value, fieldTypeClass);
                    clazz.getMethod(setMethodName, field.getType()).invoke(obj, value);
                }
            }
        }
        return obj;
    }
    private static String getMethodNameFromProperties(String propertyName){
        if(StringUtils.isEmpty(propertyName))
            return null;

        if(StringUtils.contains(propertyName, '_')) {
            char[] chars = propertyName.toCharArray();
            for(int i = 0; i<chars.length;i++) {
                if(i == 0) {
                    chars[i] = Character.toUpperCase(chars[i]);
                }
                if(chars[i] == '_') {
                    if(i+1 == chars.length)
                        continue;
                    chars[i + 1] = Character.toUpperCase(chars[i + 1]);
                }
            }
            String methodName = StringUtils.remove(String.copyValueOf(chars), '_');
            return "set" + methodName;
        } else {
            return "set"
                    + propertyName.substring(0, 1).toUpperCase()
                    + propertyName.substring(1);
        }
    }

    private static String getPropertyFromProperties(String propertyName){
        if(StringUtils.isEmpty(propertyName))
            return null;

        if(StringUtils.contains(propertyName, '_')) {
            char[] chars = propertyName.toCharArray();
            for(int i = 0; i<chars.length;i++) {
                if(chars[i] == '_') {
                    if(i+1 == chars.length)
                        continue;
                    chars[i + 1] = Character.toUpperCase(chars[i + 1]);
                }
            }
            String methodName = StringUtils.remove(String.copyValueOf(chars), '_');
            return methodName;
        } else {
            return propertyName;
        }
    }
    /**
     * 将Object类型的值，转换成bean对象属性里对应的类型值
     *
     * @param value          Object对象值
     * @param fieldTypeClass 属性的类型
     * @return 转换后的值
     */
    private static Object convertValType(Object value, Class fieldTypeClass) {
        Object retVal = null;
        if (Long.class.getName().equals(fieldTypeClass.getName())
                || long.class.getName().equals(fieldTypeClass.getName())) {
            retVal = Long.parseLong(value.toString());
        } else if (Integer.class.getName().equals(fieldTypeClass.getName())
                || int.class.getName().equals(fieldTypeClass.getName())) {
            retVal = Integer.parseInt(value.toString());
        } else if (Float.class.getName().equals(fieldTypeClass.getName())
                || float.class.getName().equals(fieldTypeClass.getName())) {
            retVal = Float.parseFloat(value.toString());
        } else if (Double.class.getName().equals(fieldTypeClass.getName())
                || double.class.getName().equals(fieldTypeClass.getName())) {
            retVal = Double.parseDouble(value.toString());
        } else {
            retVal = value;
        }
        return retVal;
    }

    /**
     * 获取指定字段名称查找在class中的对应的Field对象(包括查找父类)
     *
     * @param clazz     指定的class
     * @param fieldName 字段名称
     * @return Field对象
     */
    private static Field getClassField(Class clazz, String fieldName) {
        if (Object.class.getName().equals(clazz.getName())) {
            return null;
        }
        Field[] declaredFields = clazz.getDeclaredFields();
        for (Field field : declaredFields) {
            if (field.getName().equals(fieldName)) {
                return field;
            }
        }

        Class superClass = clazz.getSuperclass();
        if (superClass != null) {// 简单的递归一下
            return getClassField(superClass, fieldName);
        }
        return null;
    }
}
